package cn.com.dhcc.ddi.task.service.transform.impl;

import cn.com.dhcc.app.core.exception.DaoException;
import cn.com.dhcc.app.core.exception.ServiceException;
import cn.com.dhcc.app.core.service.Log;
import cn.com.dhcc.app.core.tag.CommonStaticCode;
import cn.com.dhcc.app.core.util.JsonUtil;
import cn.com.dhcc.app.core.util.UUIDGenerator;
import cn.com.dhcc.app.pub.CM;
import cn.com.dhcc.app.pub.core.consts.DdiProperties;
import cn.com.dhcc.ddi.datamapping.dao.FuncIdentifyDao;
import cn.com.dhcc.ddi.datamapping.dao.FuncMappingDao;
import cn.com.dhcc.ddi.datamapping.vo.FuncIdentify;
import cn.com.dhcc.ddi.datamapping.vo.FuncMapping;
import cn.com.dhcc.ddi.task.dao.TaskExecuteLogDao;
import cn.com.dhcc.ddi.task.service.Result;
import cn.com.dhcc.ddi.task.service.transform.FuncHandlerInterface;
import cn.com.dhcc.ddi.task.service.transform.TDataInterface;
import cn.com.dhcc.ddi.task.vo.Task;
import cn.com.dhcc.ddi.task.vo.TaskExecuteLog;
import org.apache.commons.io.FileUtils;
import org.apache.log4j.Logger;
import org.json.JSONArray;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.util.StringUtils;

import java.io.File;
import java.io.IOException;
import java.util.*;

/**
 * @日期：2017/5/9 10:41
 * @作者：张洪涛
 * @版权所有：东华软件
 * @版本：1.0
 */
@Service
public class TDataFileExchangeImpl implements TDataInterface {
    private static Logger logger = Log.getLogger(Log.LOGTYPE.DDI);
    private static Logger trans_logger = Log.getLogger("TRANS_LOG");
    @Autowired
    private TaskExecuteLogDao taskExecuteLogDao;
    @Autowired
    private FuncIdentifyDao funcIdentifyDao;
    @Autowired
    private FuncMappingDao funcMappingDao;

    @Override
    public Result transformData(Task task, String taskLogId) throws ServiceException, DaoException {
        logger.info("开始执行transform...");
        //服务器数据原文件存储目录
        String extractPath = DdiProperties.APP_UPLOAD_FILEDATA_PATH + File.separator + TaskExecuteLog.LINK_TYPE.EXTRACT.getEname() + File.separator + task.getId() + File.separator + taskLogId;
        Result result = new Result();
        result.setTaskLogId(taskLogId);
        //记录转换环节日志
        TaskExecuteLog transformLog = new TaskExecuteLog();
        transformLog.setId(UUIDGenerator.getUUID());
        transformLog.setTaskId(task.getId());
        transformLog.setLinkType(TaskExecuteLog.LINK_TYPE.TRANSFORM.getCode());
        transformLog.setLinkStartTime(new Date());
        transformLog.setMtime(new Date());
        transformLog.setGroupId(taskLogId);
        taskExecuteLogDao.insert(transformLog);
        result.setLinkLogId(transformLog.getId());
        //映射根目录
        String transformPath = DdiProperties.APP_UPLOAD_FILEDATA_PATH + File.separator + TaskExecuteLog.LINK_TYPE.TRANSFORM.getEname() + File.separator + task.getId() + File.separator + taskLogId;
        TaskExecuteLog extractLog = taskExecuteLogDao.getExtractLog(taskLogId);
        if (extractLog.getLogStatus().equalsIgnoreCase(CommonStaticCode.SUCCESSFAIL.FAIL.getStatus()) || extractLog.getLogStatus().equalsIgnoreCase("") || extractLog.getLogStatus() == null) {
            result.setStatus(CommonStaticCode.SUCCESSFAIL.FAIL.getStatus());
            result.setMsg("抽取数据失败");
            if (extractLog.getLogStatus().equalsIgnoreCase("") || extractLog.getLogStatus() == null) {
                extractLog.setLogStatus(CommonStaticCode.SUCCESSFAIL.FAIL.getStatus());
                extractLog.setLinkEndTime(new Date());
                taskExecuteLogDao.update(extractLog);
            }
            return result;
        }

        if (extractLog.getTotal() == 0) {
            String msg = "本次任务没有交换数据.";
            result.setStatus(CommonStaticCode.SUCCESSFAIL.SUCCESS.getStatus());
            result.setMsg(msg);
            transformLog.setLogStatus(CommonStaticCode.SUCCESSFAIL.SUCCESS.getStatus());
            transformLog.setLinkEndTime(new Date());
            transformLog.setLinkSummary(msg);
            transformLog.setTotal(0);
            taskExecuteLogDao.update(transformLog);
            return result;
        }

        //先复制新的文件到指定目录中，操作复制后的数据文件，防止读取文件过程中错误，导致文件失效
        //文件名称
        List<String> fileDirList = new ArrayList<String>();
        //文件服务器存储路径
        List<File> fileList = new ArrayList<File>();
        //文件相对路径
        List<String> fileRelativePath = new ArrayList<String>();

        List<String> filePathList = JsonUtil.toObjectList(extractLog.getLinkDataFilePath(), String.class);
        File transformFolder = new File(transformPath);
        if (!transformFolder.exists()) {
            transformFolder.mkdir();
        }
        if (StringUtils.isEmpty(filePathList)) {
            logger.error("获取到数据抽取文件路径失败。路径为空。");
            //如果查询出的文件目录为空，则不进行复制，只更新数据库状态，不进行后续操作
            result.setStatus(CommonStaticCode.SUCCESSFAIL.FAIL.getStatus());
            result.setMsg("获取到数据抽取文件路径失败。路径为空。");
            return result;
        }
        logger.info("[transform]开始复制文件...");
        for (String relativePath : filePathList) {
            String outDataPath = transformPath + File.separator + relativePath;
            File extractDataFile = new File(extractPath + File.separator + relativePath);
            File outFile = new File(outDataPath);
            try {
                FileUtils.copyFile(extractDataFile, outFile);
                fileList.add(outFile);
                fileDirList.add(outFile.getAbsolutePath());
            } catch (IOException e) {
                logger.error("[transform]copy " + extractDataFile + " 发生异常", e);
                result.setStatus(CommonStaticCode.SUCCESSFAIL.FAIL.getStatus());
                result.setMsg("[transform]copy " + extractDataFile + " 发生异常");
                return result;
            }
        }
        logger.info("[transform]文件复制完成...开始映射...");
        Map<File, File> transMap = convert(fileList,task.getMpId(),transformPath);
        String linkSummary = "";
        for (File f : transMap.keySet()) {
            File dest = transMap.get(f);
            String relativePath = dest.getAbsolutePath().substring(transformPath.length() + 1);
            fileRelativePath.add(relativePath);
        }
        transformFolder.delete();
        if(transMap.size() == extractLog.getTotal()){
            transformLog.setLinkDataFilePath(JsonUtil.toJson(fileRelativePath));
            linkSummary = createTransContentDetail(transMap);
            transformLog.setTotal(transMap.size());
            transformLog.setLogStatus(CommonStaticCode.SUCCESSFAIL.SUCCESS.getStatus());
            result.setStatus(CommonStaticCode.SUCCESSFAIL.SUCCESS.getStatus());
            result.setMsg("[transform]成功 ");
        }else{
            linkSummary = "映射失败";
            transformLog.setLogStatus(CommonStaticCode.SUCCESSFAIL.FAIL.getStatus());
            result.setStatus(CommonStaticCode.SUCCESSFAIL.FAIL.getStatus());
            result.setMsg("[transform]映射失败 ");
        }
        transformLog.setLinkSummary(linkSummary);
        transformLog.setLinkEndTime(new Date());
        taskExecuteLogDao.update(transformLog);
        return result;
    }

    /**
     * 数据映射
     *
     * @param files
     * @param mappingId
     */
    public Map<File, File> convert(List<File> files, String mappingId,String transformPath) throws DaoException {
        List<FuncMapping> mps = funcMappingDao.getList(mappingId);
        Map<String, FuncIdentify> funcs = getFuncIdentifys();
        //文件映射的对应信息 原名--映射后的文件名
        Map<File, File> dmMap = new LinkedHashMap<File, File>();
        for (File f : files) {
            //拆分扩展名和文件名
            String extension = f.getName().substring(f.getName().lastIndexOf("."));
            String oldName = f.getName().substring(0,f.getName().lastIndexOf("."));
            String newName = oldName;
            try {
                for (FuncMapping fm : mps) {
                    FuncIdentify func = funcs.get(fm.getFxId());
                    String fxName = func.getFxNameEn();
                    List<String> args = new ArrayList<String>();
                    args.add(oldName);
                    if (!fm.getArgContent().isEmpty()) {
                        List<String> argsList = getArgs(fm.getArgContent());
                        args.addAll(argsList);
                    }
                    FuncHandlerInterface handler = getFuncHandlerInterface(func);
                    newName = (String) handler.call(fxName, args);
                    newName += extension;
                }
            } catch (Exception e) {
                trans_logger.error("映射函数调用失败",e);
            }
            //映射后文件
            File dest = new File(transformPath,newName);

            if(newName.equals(oldName)){
                dmMap.put(f,dest);
                continue;
            }
            if (f.renameTo(dest)){
                dmMap.put(f,dest);
            }
        }
        return dmMap;
    }

    /**
     * 获取所有函数
     *
     * @return
     * @throws DaoException
     */
    private Map<String, FuncIdentify> getFuncIdentifys() throws DaoException {
        Map<String, FuncIdentify> map = new HashMap<String, FuncIdentify>();
        List<FuncIdentify> funcs = funcIdentifyDao.list();
        for (FuncIdentify func : funcs) {
            map.put(func.getId(), func);
        }
        return map;
    }

    /**
     * 解析映射函数参数
     *
     * @param argContent 参数内容
     * @return
     */
    private List<String> getArgs(String argContent) {
        List<String> args = new ArrayList<String>();
        if (argContent == null || argContent.isEmpty()) {
            return args;
        }
        JSONArray array = new JSONArray(argContent);
        for (int i = 0; i < array.length(); i++) {
            String arg = array.get(i).toString();
            Map<String, String> map = JsonUtil.toMap(arg);
            for (String key : map.keySet()) {
                args.add(map.get(key));
            }
        }
        return args;
    }

    /**
     * 获取函数处理类
     *
     * @param func 函数
     * @return
     */
    private FuncHandlerInterface getFuncHandlerInterface(FuncIdentify func) {
        return CM.getBean(FuncIdentify.FUNC_TYPE.find(func.getIsCustomized()).getHandler());
    }

    /**
     * 生成映射详情
     * @param transMap 映射结果记录
     * @return
     */
    private String  createTransContentDetail(  Map<File, File> transMap)  {
        logger.info("进入方法createCendContentDetail().");
        StringBuilder rs = new StringBuilder();
        //将转换前后的表名对应关系取出
        int sum = 0;
        StringBuilder files = new StringBuilder();
        for (File f : transMap.keySet()) {
            File dest = transMap.get(f);
            files.append("文件：").append(f.getName()).append(" -> ").append(dest.getName()).append("\r\n");
        }
        rs.append("数据映射结果,总数:").append(transMap.size()).append("\r\n").append(files);
        logger.info("执行结束createTransContentDetail().返回值：" + rs.toString());
        return rs.toString();
    }
}
